"""
态势对象关系业务逻辑服务层
"""
from typing import List, Optional, Set, Tuple
from uuid import UUID
from datetime import datetime
from sqlalchemy import select, func, and_, or_
from sqlalchemy.ext.asyncio import AsyncSession

from src.situation.relationship_models import SituationRelationship
from src.situation.models import SituationObject
from src.situation.relationship_schemas import (
    RelationshipCreate,
    RelationshipUpdate,
    RelationshipResponse,
    RelationshipListResponse,
    RelationshipFilter,
    RelationshipTreeNode,
    CycleCheckResponse,
)
from src.utils import logger


class RelationshipService:
    """态势对象关系服务类"""

    @staticmethod
    async def create_relationship(db: AsyncSession, rel_data: RelationshipCreate, user: Optional[str] = None) -> RelationshipResponse:
        """
        创建态势对象关系

        Args:
            db: 数据库会话
            rel_data: 关系数据
            user: 创建用户

        Returns:
            创建后的关系
        """
        logger.info(f"[关系管理] 开始创建关系: {rel_data.source_object_id} -> {rel_data.target_object_id}, type={rel_data.relationship_type}")

        # 1. 验证源对象和目标对象是否存在
        await RelationshipService._validate_objects_exist(db, rel_data.source_object_id, rel_data.target_object_id)

        # 2. 验证关系类型是否有效
        RelationshipService._validate_relationship_type(rel_data.relationship_type)

        # 3. 自动计算关系层级
        calculated_level = await RelationshipService._calculate_relationship_level(db, rel_data.source_object_id)
        logger.info(f"[关系管理] 计算得到的关系层级: {calculated_level}")

        # 4. 检查是否超过最大层级限制
        if calculated_level > 5:
            raise ValueError(f"关系层级不能超过5级,当前源对象已处于{calculated_level - 1}级,无法继续添加子关系")

        # 5. 检查是否存在循环依赖
        has_cycle = await RelationshipService.check_cycle(db, rel_data.source_object_id, rel_data.target_object_id, rel_data.relationship_type)
        if has_cycle.has_cycle:
            raise ValueError(f"创建关系会导致循环依赖: {has_cycle.message}")

        # 5. 检查关系是否已存在
        existing_stmt = select(SituationRelationship).where(
            and_(
                SituationRelationship.source_object_id == rel_data.source_object_id,
                SituationRelationship.target_object_id == rel_data.target_object_id,
                SituationRelationship.relationship_type == rel_data.relationship_type,
                SituationRelationship.is_deleted == False,  # noqa: E712
            )
        )
        existing_result = await db.execute(existing_stmt)
        if existing_result.scalar_one_or_none():
            raise ValueError("该关系已存在")

        # 6. 创建关系(使用自动计算的层级)
        db_rel = SituationRelationship(
            source_object_id=rel_data.source_object_id,
            target_object_id=rel_data.target_object_id,
            relationship_type=rel_data.relationship_type,
            relationship_level=calculated_level,  # 使用自动计算的层级
            properties=rel_data.properties or {},
            description=rel_data.description,
            created_by=user,
        )

        db.add(db_rel)
        await db.commit()
        await db.refresh(db_rel)

        logger.info(f"[关系管理] 创建关系成功: {db_rel.id}, level={db_rel.relationship_level}")
        return await RelationshipService._build_response(db, db_rel)

    @staticmethod
    async def _validate_objects_exist(db: AsyncSession, source_id: UUID, target_id: UUID):
        """验证对象是否存在"""
        for obj_id in [source_id, target_id]:
            stmt = select(SituationObject).where(and_(SituationObject.id == obj_id, SituationObject.is_deleted == False))  # noqa: E712
            result = await db.execute(stmt)
            if not result.scalar_one_or_none():
                raise ValueError(f"对象不存在: {obj_id}")

    @staticmethod
    async def _calculate_relationship_level(db: AsyncSession, source_object_id: UUID) -> int:
        """
        计算关系层级

        逻辑:
        - 如果源对象没有任何入边(没有其他对象指向它),则层级为1(一级关系)
        - 如果源对象有入边,则找出所有指向它的关系中最大的层级,新关系层级 = 最大层级 + 1
        - 例如: A->B(level=1), B->C 则 level=2

        Args:
            db: 数据库会话
            source_object_id: 源对象ID

        Returns:
            计算得到的关系层级
        """
        # 查询所有指向源对象的关系(源对象作为目标对象的关系)
        stmt = select(func.max(SituationRelationship.relationship_level)).where(
            and_(
                SituationRelationship.target_object_id == source_object_id,
                SituationRelationship.is_deleted == False  # noqa: E712
            )
        )
        result = await db.execute(stmt)
        max_parent_level = result.scalar()

        # 如果没有入边,说明是根节点,层级为1
        if max_parent_level is None:
            return 1

        # 否则层级 = 父节点最大层级 + 1
        return max_parent_level + 1

    @staticmethod
    async def check_cycle(db: AsyncSession, source_id: UUID, target_id: UUID, relationship_type: str) -> CycleCheckResponse:
        """
        检测循环依赖

        使用 DFS 从 target_id 开始遍历,检查是否能回到 source_id

        Args:
            db: 数据库会话
            source_id: 源对象ID
            target_id: 目标对象ID
            relationship_type: 关系类型

        Returns:
            循环检测结果
        """
        logger.info(f"[循环检测] 开始检测: {source_id} -> {target_id}")

        visited: Set[UUID] = set()
        path: List[UUID] = []

        async def dfs(current_id: UUID) -> bool:
            """深度优先搜索"""
            if current_id == source_id:
                path.append(current_id)
                return True

            if current_id in visited:
                return False

            visited.add(current_id)
            path.append(current_id)

            # 查询当前节点的所有出边
            stmt = select(SituationRelationship).where(
                and_(
                    SituationRelationship.source_object_id == current_id,
                    SituationRelationship.is_deleted == False,  # noqa: E712
                )
            )
            result = await db.execute(stmt)
            relationships = result.scalars().all()

            for rel in relationships:
                if await dfs(rel.target_object_id):
                    return True

            path.pop()
            return False

        has_cycle = await dfs(target_id)

        if has_cycle:
            logger.warning(f"[循环检测] 检测到循环: {' -> '.join(str(p) for p in path)}")
            return CycleCheckResponse(has_cycle=True, cycle_path=path, message=f"存在循环路径,包含 {len(path)} 个节点")
        else:
            logger.info(f"[循环检测] 未检测到循环")
            return CycleCheckResponse(has_cycle=False, cycle_path=None, message="未检测到循环依赖")

    @staticmethod
    async def get_relationship(db: AsyncSession, relationship_id: UUID) -> Optional[RelationshipResponse]:
        """获取单个关系"""
        stmt = select(SituationRelationship).where(and_(SituationRelationship.id == relationship_id, SituationRelationship.is_deleted == False))  # noqa: E712
        result = await db.execute(stmt)
        db_rel = result.scalar_one_or_none()

        if db_rel:
            return await RelationshipService._build_response(db, db_rel)
        return None

    @staticmethod
    async def list_relationships(db: AsyncSession, page: int = 1, page_size: int = 20, filters: Optional[RelationshipFilter] = None) -> RelationshipListResponse:
        """获取关系列表"""
        conditions = [SituationRelationship.is_deleted == False]  # noqa: E712

        if filters:
            if filters.source_object_id:
                conditions.append(SituationRelationship.source_object_id == filters.source_object_id)
            if filters.target_object_id:
                conditions.append(SituationRelationship.target_object_id == filters.target_object_id)
            if filters.relationship_type:
                conditions.append(SituationRelationship.relationship_type == filters.relationship_type)
            if filters.relationship_level:
                conditions.append(SituationRelationship.relationship_level == filters.relationship_level)

        # 查询总数
        count_stmt = select(func.count()).select_from(SituationRelationship).where(and_(*conditions))
        total_result = await db.execute(count_stmt)
        total = total_result.scalar()

        # 查询分页数据
        offset = (page - 1) * page_size
        stmt = select(SituationRelationship).where(and_(*conditions)).order_by(SituationRelationship.created_at.desc()).offset(offset).limit(page_size)
        result = await db.execute(stmt)
        items = result.scalars().all()

        # 构建响应
        response_items = []
        for item in items:
            response_items.append(await RelationshipService._build_response(db, item))

        return RelationshipListResponse(total=total, items=response_items, page=page, page_size=page_size)

    @staticmethod
    async def update_relationship(db: AsyncSession, relationship_id: UUID, rel_data: RelationshipUpdate, user: Optional[str] = None) -> Optional[RelationshipResponse]:
        """更新关系"""
        stmt = select(SituationRelationship).where(and_(SituationRelationship.id == relationship_id, SituationRelationship.is_deleted == False))  # noqa: E712
        result = await db.execute(stmt)
        db_rel = result.scalar_one_or_none()

        if not db_rel:
            return None

        # 更新字段
        update_data = rel_data.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            if value is not None:
                # 如果更新关系类型，验证其有效性
                if field == "relationship_type":
                    RelationshipService._validate_relationship_type(value)
                setattr(db_rel, field, value)

        db_rel.updated_by = user
        db_rel.updated_at = datetime.utcnow()

        await db.commit()
        await db.refresh(db_rel)

        logger.info(f"[关系管理] 更新关系成功: {relationship_id}")
        return await RelationshipService._build_response(db, db_rel)

    @staticmethod
    async def delete_relationship(db: AsyncSession, relationship_id: UUID, user: Optional[str] = None) -> bool:
        """删除关系(软删除)"""
        stmt = select(SituationRelationship).where(and_(SituationRelationship.id == relationship_id, SituationRelationship.is_deleted == False))  # noqa: E712
        result = await db.execute(stmt)
        db_rel = result.scalar_one_or_none()

        if not db_rel:
            return False

        db_rel.is_deleted = True
        db_rel.deleted_at = datetime.utcnow()
        db_rel.updated_by = user

        await db.commit()
        logger.info(f"[关系管理] 删除关系成功: {relationship_id}")
        return True

    @staticmethod
    async def get_relationship_tree(db: AsyncSession, root_object_id: UUID, max_level: int = 5) -> RelationshipTreeNode:
        """
        递归查询关系树

        Args:
            db: 数据库会话
            root_object_id: 根对象ID
            max_level: 最大层级(1-5)

        Returns:
            关系树
        """
        logger.info(f"[关系树] 开始构建关系树: root={root_object_id}, max_level={max_level}")

        # 获取根对象
        root_stmt = select(SituationObject).where(and_(SituationObject.id == root_object_id, SituationObject.is_deleted == False))  # noqa: E712
        root_result = await db.execute(root_stmt)
        root_obj = root_result.scalar_one_or_none()

        if not root_obj:
            raise ValueError(f"根对象不存在: {root_object_id}")

        # 构建根节点
        root_node = RelationshipTreeNode(
            object_id=root_obj.id, object_name=root_obj.name, object_code=root_obj.code, object_type=root_obj.object_type, relationship_type=None, relationship_id=None, level=1, children=[]
        )

        # 递归构建子节点
        visited: Set[UUID] = {root_object_id}
        await RelationshipService._build_tree_recursive(db, root_node, visited, max_level)

        logger.info(f"[关系树] 关系树构建完成")
        return root_node

    @staticmethod
    async def _build_tree_recursive(db: AsyncSession, parent_node: RelationshipTreeNode, visited: Set[UUID], max_level: int):
        """递归构建关系树"""
        if parent_node.level >= max_level:
            return

        # 查询子关系
        stmt = select(SituationRelationship).where(
            and_(SituationRelationship.source_object_id == parent_node.object_id, SituationRelationship.is_deleted == False)  # noqa: E712
        )
        result = await db.execute(stmt)
        relationships = result.scalars().all()

        for rel in relationships:
            # 避免循环
            if rel.target_object_id in visited:
                continue

            # 获取目标对象
            target_stmt = select(SituationObject).where(and_(SituationObject.id == rel.target_object_id, SituationObject.is_deleted == False))  # noqa: E712
            target_result = await db.execute(target_stmt)
            target_obj = target_result.scalar_one_or_none()

            if not target_obj:
                continue

            # 创建子节点
            child_node = RelationshipTreeNode(
                object_id=target_obj.id,
                object_name=target_obj.name,
                object_code=target_obj.code,
                object_type=target_obj.object_type,
                relationship_type=rel.relationship_type,
                relationship_id=rel.id,
                level=parent_node.level + 1,
                children=[],
            )

            parent_node.children.append(child_node)
            visited.add(target_obj.id)

            # 递归构建
            await RelationshipService._build_tree_recursive(db, child_node, visited, max_level)

    @staticmethod
    async def _build_response(db: AsyncSession, db_rel: SituationRelationship) -> RelationshipResponse:
        """构建关系响应对象,包含关联对象信息"""
        # 查询源对象和目标对象
        source_stmt = select(SituationObject).where(SituationObject.id == db_rel.source_object_id)
        target_stmt = select(SituationObject).where(SituationObject.id == db_rel.target_object_id)

        source_result = await db.execute(source_stmt)
        target_result = await db.execute(target_stmt)

        source_obj = source_result.scalar_one_or_none()
        target_obj = target_result.scalar_one_or_none()

        return RelationshipResponse(
            id=db_rel.id,
            source_object_id=db_rel.source_object_id,
            target_object_id=db_rel.target_object_id,
            relationship_type=db_rel.relationship_type,
            relationship_level=db_rel.relationship_level,
            properties=db_rel.properties or {},
            description=db_rel.description,
            source_object_name=source_obj.name if source_obj else None,
            source_object_code=source_obj.code if source_obj else None,
            target_object_name=target_obj.name if target_obj else None,
            target_object_code=target_obj.code if target_obj else None,
            created_at=db_rel.created_at,
            updated_at=db_rel.updated_at,
            created_by=db_rel.created_by,
            updated_by=db_rel.updated_by,
        )

    @staticmethod
    def _validate_relationship_type(relationship_type: str):
        """验证关系类型是否有效"""
        from src.situation.models import RelationshipTypeEnum
        valid_types = [enum_value.value for enum_value in RelationshipTypeEnum]
        if relationship_type not in valid_types:
            valid_types_str = ", ".join(valid_types)
            raise ValueError(f"无效的关系类型 '{relationship_type}'，有效类型包括: {valid_types_str}")

    @staticmethod
    def get_relationship_types():
        """获取所有关系类型"""
        from src.situation.relationship_schemas import get_relationship_types
        return get_relationship_types()
